package wxpay

import (
	"bytes"
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"time"
)

// ----------payClient(支付 http 客户端) - 与微信后台通信模块 --------------//

type CompanyPayClient struct {
	httpClient *http.Client
}

func NewCompanyPayClient(httpClient *http.Client) *PayClient  {
	if httpClient == nil {
		httpClient = http.DefaultClient
		httpClient.Timeout = time.Second * 5
	}

	return &PayClient{
		httpClient:httpClient,
	}
}

func NewCertCompanyPayClient() *PayClient {
	var wechatPayCert = "./configs/certs/company/apiclient_cert.pem"
	var wechatPayKey = "./configs/certs/company/apiclient_key.pem"

	certs, _ := tls.LoadX509KeyPair(wechatPayCert, wechatPayKey)

	client := &http.Client{
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				RootCAs:      nil,
				Certificates: []tls.Certificate{certs},
			},
		},
	}
	return NewPayClient(client)
}

// post 请求
func (pc *CompanyPayClient) PostXML(url string, pdata *PayData, apiKey string) (*PayData, error)  {
	reqSignType := pdata.Get("sign")
	req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(pdata.ToXml()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "text/xml; charset=utf-8")

	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	req = req.WithContext(ctx)
	httpResp, err := pc.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()

	if httpResp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http.Status: %s", httpResp.Status)
	}

	respData := NewPayData()
	err = respData.FromXml(httpResp.Body)
	//log.Println("respData",respData)
	if err != nil {
		return nil, err
	}
	err = respData.CheckSign(apiKey, reqSignType)
	if err != nil {
		return nil, err
	}

	return respData, nil
}

func (pc *CompanyPayClient) PostXMLNoCheckSign(url string, pdata *PayData) (*PayData, error)  {
	//reqSignType := pdata.Get("sign")
	req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(pdata.ToXml()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "text/xml; charset=utf-8")

	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	req = req.WithContext(ctx)
	httpResp, err := pc.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()

	if httpResp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http.Status: %s", httpResp.Status)
	}

	respData := NewPayData()
	err = respData.FromXml(httpResp.Body)
	//log.Println("respData",respData)
	if err != nil {
		return nil, err
	}

	return respData, nil
}

func (pc *CompanyPayClient) PostJson(url string, body []byte, token string) (*PayData, error)  {
	req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(body))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json; charset=utf-8")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Authorization", token)

	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	req = req.WithContext(ctx)
	httpResp, err := pc.httpClient.Do(req)

	if err != nil {
		return nil, err
	}
	defer httpResp.Body.Close()

	if httpResp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http.Status: %s", httpResp.Status)
	}

	respData := NewPayData()
	err = respData.FromJson(httpResp.Body)
	if err != nil {
		return nil, err
	}

	return respData, nil
}